@krodak/clickup-cli 1.5.1 → 1.6.0
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/.claude-plugin/plugin.json +1 -1
- package/README.md +28 -4
- package/dist/index.js +407 -110
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +24 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clickup-cli",
|
|
3
3
|
"description": "ClickUp CLI skills for managing tasks, sprints, comments, checklists, custom fields, tags, and time tracking via the cup command",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Krzysztof Rodak"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -165,18 +165,41 @@ Most commands scope to your assigned tasks by default - keeping output small and
|
|
|
165
165
|
|
|
166
166
|
## Configuration
|
|
167
167
|
|
|
168
|
+
### Profiles
|
|
169
|
+
|
|
170
|
+
Multiple profiles for different workspaces or accounts:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
cup profile add work # interactive setup
|
|
174
|
+
cup profile add personal # another workspace
|
|
175
|
+
cup profile list # show all profiles
|
|
176
|
+
cup profile use personal # switch default
|
|
177
|
+
cup tasks -p work # one-off profile override
|
|
178
|
+
```
|
|
179
|
+
|
|
168
180
|
### Config file
|
|
169
181
|
|
|
170
182
|
`~/.config/cup/config.json` (or `$XDG_CONFIG_HOME/cup/config.json`):
|
|
171
183
|
|
|
172
184
|
```json
|
|
173
185
|
{
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
|
|
186
|
+
"defaultProfile": "work",
|
|
187
|
+
"profiles": {
|
|
188
|
+
"work": {
|
|
189
|
+
"apiToken": "pk_...",
|
|
190
|
+
"teamId": "12345678",
|
|
191
|
+
"sprintFolderId": "optional"
|
|
192
|
+
},
|
|
193
|
+
"personal": {
|
|
194
|
+
"apiToken": "pk_...",
|
|
195
|
+
"teamId": "87654321"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
177
198
|
}
|
|
178
199
|
```
|
|
179
200
|
|
|
201
|
+
Old flat configs (pre-profiles) are auto-migrated on first load.
|
|
202
|
+
|
|
180
203
|
### Environment variables
|
|
181
204
|
|
|
182
205
|
Environment variables override config file values:
|
|
@@ -185,9 +208,10 @@ Environment variables override config file values:
|
|
|
185
208
|
| -------------- | ----------------------------------------------------------------- |
|
|
186
209
|
| `CU_API_TOKEN` | ClickUp personal API token (`pk_`) |
|
|
187
210
|
| `CU_TEAM_ID` | Workspace (team) ID |
|
|
211
|
+
| `CU_PROFILE` | Profile name (overrides `defaultProfile`, overridden by `-p`) |
|
|
188
212
|
| `CU_OUTPUT` | Set to `json` to force JSON output when piped (default: markdown) |
|
|
189
213
|
|
|
190
|
-
When both are set, the config file is not required. Useful for CI/CD and containerized agents.
|
|
214
|
+
When both `CU_API_TOKEN` and `CU_TEAM_ID` are set, the config file is not required. Useful for CI/CD and containerized agents.
|
|
191
215
|
|
|
192
216
|
## Custom Task IDs
|
|
193
217
|
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
+
import { realpathSync } from "fs";
|
|
4
5
|
import { basename, resolve } from "path";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
import { createRequire } from "module";
|
|
@@ -740,62 +741,243 @@ function migrateFromLegacy() {
|
|
|
740
741
|
function configPath() {
|
|
741
742
|
return join(configDir(), "config.json");
|
|
742
743
|
}
|
|
743
|
-
function
|
|
744
|
+
function migrateToMultiProfile(parsed, filePath) {
|
|
745
|
+
if (typeof parsed.apiToken === "string" && !parsed.profiles) {
|
|
746
|
+
const profile = {};
|
|
747
|
+
const token = trimConfigValue(parsed.apiToken);
|
|
748
|
+
if (token) profile.apiToken = token;
|
|
749
|
+
const team = typeof parsed.teamId === "string" ? trimConfigValue(parsed.teamId) : void 0;
|
|
750
|
+
if (team) profile.teamId = team;
|
|
751
|
+
const sprint = typeof parsed.sprintFolderId === "string" ? trimConfigValue(parsed.sprintFolderId) : void 0;
|
|
752
|
+
if (sprint) profile.sprintFolderId = sprint;
|
|
753
|
+
const migrated = {
|
|
754
|
+
defaultProfile: "default",
|
|
755
|
+
profiles: { default: profile }
|
|
756
|
+
};
|
|
757
|
+
const dir = configDir();
|
|
758
|
+
if (!fs.existsSync(dir)) {
|
|
759
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
760
|
+
}
|
|
761
|
+
fs.writeFileSync(join(dir, "config.json"), JSON.stringify(migrated, null, 2) + "\n", {
|
|
762
|
+
encoding: "utf-8",
|
|
763
|
+
mode: 384
|
|
764
|
+
});
|
|
765
|
+
return migrated;
|
|
766
|
+
}
|
|
767
|
+
if (isRecord2(parsed.profiles)) {
|
|
768
|
+
const profiles = {};
|
|
769
|
+
for (const [name, value] of Object.entries(parsed.profiles)) {
|
|
770
|
+
if (isRecord2(value)) {
|
|
771
|
+
const p = {};
|
|
772
|
+
if (typeof value.apiToken === "string" && value.apiToken.trim())
|
|
773
|
+
p.apiToken = value.apiToken.trim();
|
|
774
|
+
if (typeof value.teamId === "string" && value.teamId.trim()) p.teamId = value.teamId.trim();
|
|
775
|
+
if (typeof value.sprintFolderId === "string" && value.sprintFolderId.trim())
|
|
776
|
+
p.sprintFolderId = value.sprintFolderId.trim();
|
|
777
|
+
profiles[name] = p;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return {
|
|
781
|
+
defaultProfile: typeof parsed.defaultProfile === "string" ? parsed.defaultProfile : "",
|
|
782
|
+
profiles
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
throw new Error(`Config file at ${filePath} has unrecognized format.`);
|
|
786
|
+
}
|
|
787
|
+
function parseRawConfig(filePath) {
|
|
788
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
789
|
+
let parsed;
|
|
790
|
+
try {
|
|
791
|
+
parsed = JSON.parse(raw);
|
|
792
|
+
} catch {
|
|
793
|
+
throw new Error(
|
|
794
|
+
`Config file at ${filePath} contains invalid JSON. Please check the file syntax.`
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
if (!isRecord2(parsed)) {
|
|
798
|
+
throw new Error(`Config file at ${filePath} must contain a JSON object.`);
|
|
799
|
+
}
|
|
800
|
+
return { parsed, raw };
|
|
801
|
+
}
|
|
802
|
+
function isOldFormat(parsed) {
|
|
803
|
+
return typeof parsed.apiToken === "string" && !parsed.profiles;
|
|
804
|
+
}
|
|
805
|
+
function loadConfig(profileName) {
|
|
744
806
|
migrateFromLegacy();
|
|
745
807
|
const envToken = process.env.CU_API_TOKEN?.trim();
|
|
746
808
|
const envTeamId = process.env.CU_TEAM_ID?.trim();
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
809
|
+
if (envToken && envTeamId) {
|
|
810
|
+
if (!envToken.startsWith("pk_")) {
|
|
811
|
+
throw new Error("CU_API_TOKEN must start with pk_.");
|
|
812
|
+
}
|
|
813
|
+
return { apiToken: envToken, teamId: envTeamId };
|
|
814
|
+
}
|
|
750
815
|
const path = configPath();
|
|
751
|
-
if (fs.existsSync(path)) {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
816
|
+
if (!fs.existsSync(path)) {
|
|
817
|
+
if (envToken || envTeamId) {
|
|
818
|
+
throw new Error("Both CU_API_TOKEN and CU_TEAM_ID must be set, or run: cup init");
|
|
819
|
+
}
|
|
820
|
+
throw new Error("Config missing required field: apiToken.\nSet CU_API_TOKEN or run: cup init");
|
|
821
|
+
}
|
|
822
|
+
const { parsed } = parseRawConfig(path);
|
|
823
|
+
if (isOldFormat(parsed)) {
|
|
824
|
+
const fileConfig = parseConfigFile(JSON.stringify(parsed), path, true);
|
|
825
|
+
const apiToken2 = envToken ?? fileConfig.apiToken;
|
|
826
|
+
if (!apiToken2) {
|
|
827
|
+
throw new Error("Config missing required field: apiToken.\nSet CU_API_TOKEN or run: cup init");
|
|
828
|
+
}
|
|
829
|
+
if (!apiToken2.startsWith("pk_")) {
|
|
830
|
+
throw new Error("Config apiToken must start with pk_. The configured token does not.");
|
|
831
|
+
}
|
|
832
|
+
const teamId2 = envTeamId ?? fileConfig.teamId;
|
|
833
|
+
if (!teamId2) {
|
|
834
|
+
throw new Error("Config missing required field: teamId.\nSet CU_TEAM_ID or run: cup init");
|
|
835
|
+
}
|
|
836
|
+
migrateToMultiProfile(parsed, path);
|
|
837
|
+
return {
|
|
838
|
+
apiToken: apiToken2,
|
|
839
|
+
teamId: teamId2,
|
|
840
|
+
...fileConfig.sprintFolderId ? { sprintFolderId: fileConfig.sprintFolderId } : {}
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
const multi = migrateToMultiProfile(parsed, path);
|
|
844
|
+
const resolvedProfile = profileName ?? process.env.CU_PROFILE?.trim() ?? multi.defaultProfile;
|
|
845
|
+
if (!resolvedProfile) {
|
|
846
|
+
throw new Error("No default profile set. Run: cup profile use <name>");
|
|
757
847
|
}
|
|
758
|
-
const
|
|
848
|
+
const profile = multi.profiles[resolvedProfile];
|
|
849
|
+
if (!profile) {
|
|
850
|
+
const available = Object.keys(multi.profiles).join(", ");
|
|
851
|
+
throw new Error(`Profile "${resolvedProfile}" not found. Available: ${available}`);
|
|
852
|
+
}
|
|
853
|
+
const apiToken = envToken ?? profile.apiToken?.trim();
|
|
759
854
|
if (!apiToken) {
|
|
760
|
-
throw new Error(
|
|
855
|
+
throw new Error(
|
|
856
|
+
`Profile "${resolvedProfile}" missing apiToken. Run: cup profile add ${resolvedProfile}`
|
|
857
|
+
);
|
|
761
858
|
}
|
|
762
859
|
if (!apiToken.startsWith("pk_")) {
|
|
763
860
|
throw new Error("Config apiToken must start with pk_. The configured token does not.");
|
|
764
861
|
}
|
|
765
|
-
const teamId = envTeamId
|
|
862
|
+
const teamId = envTeamId ?? profile.teamId?.trim();
|
|
766
863
|
if (!teamId) {
|
|
767
|
-
throw new Error("
|
|
864
|
+
throw new Error(`Profile "${resolvedProfile}" missing teamId.`);
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
867
|
+
apiToken,
|
|
868
|
+
teamId,
|
|
869
|
+
...profile.sprintFolderId ? { sprintFolderId: profile.sprintFolderId } : {}
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
function loadMultiProfileConfig() {
|
|
873
|
+
migrateFromLegacy();
|
|
874
|
+
const path = configPath();
|
|
875
|
+
if (!fs.existsSync(path)) {
|
|
876
|
+
return { defaultProfile: "", profiles: {} };
|
|
877
|
+
}
|
|
878
|
+
let parsed;
|
|
879
|
+
try {
|
|
880
|
+
const raw = fs.readFileSync(path, "utf-8");
|
|
881
|
+
parsed = JSON.parse(raw);
|
|
882
|
+
} catch {
|
|
883
|
+
return { defaultProfile: "", profiles: {} };
|
|
884
|
+
}
|
|
885
|
+
if (!isRecord2(parsed)) return { defaultProfile: "", profiles: {} };
|
|
886
|
+
if (isOldFormat(parsed)) {
|
|
887
|
+
return migrateToMultiProfile(parsed, path);
|
|
768
888
|
}
|
|
769
|
-
return
|
|
889
|
+
return migrateToMultiProfile(parsed, path);
|
|
770
890
|
}
|
|
771
|
-
function
|
|
891
|
+
function saveMultiProfileConfig(config) {
|
|
892
|
+
const dir = configDir();
|
|
893
|
+
if (!fs.existsSync(dir)) {
|
|
894
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
895
|
+
}
|
|
896
|
+
fs.writeFileSync(join(dir, "config.json"), JSON.stringify(config, null, 2) + "\n", {
|
|
897
|
+
encoding: "utf-8",
|
|
898
|
+
mode: 384
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
function addProfile(name, profile) {
|
|
902
|
+
const multi = loadMultiProfileConfig();
|
|
903
|
+
multi.profiles[name] = profile;
|
|
904
|
+
if (!multi.defaultProfile) multi.defaultProfile = name;
|
|
905
|
+
saveMultiProfileConfig(multi);
|
|
906
|
+
}
|
|
907
|
+
function removeProfile(name) {
|
|
908
|
+
const multi = loadMultiProfileConfig();
|
|
909
|
+
if (!multi.profiles[name]) {
|
|
910
|
+
throw new Error(`Profile "${name}" not found.`);
|
|
911
|
+
}
|
|
912
|
+
const keys = Object.keys(multi.profiles);
|
|
913
|
+
if (keys.length <= 1) {
|
|
914
|
+
throw new Error("Cannot remove the last profile.");
|
|
915
|
+
}
|
|
916
|
+
delete multi.profiles[name];
|
|
917
|
+
if (multi.defaultProfile === name) {
|
|
918
|
+
multi.defaultProfile = Object.keys(multi.profiles)[0] ?? "";
|
|
919
|
+
}
|
|
920
|
+
saveMultiProfileConfig(multi);
|
|
921
|
+
}
|
|
922
|
+
function setDefaultProfile(name) {
|
|
923
|
+
const multi = loadMultiProfileConfig();
|
|
924
|
+
if (!multi.profiles[name]) {
|
|
925
|
+
const available = Object.keys(multi.profiles).join(", ");
|
|
926
|
+
throw new Error(`Profile "${name}" not found. Available: ${available}`);
|
|
927
|
+
}
|
|
928
|
+
multi.defaultProfile = name;
|
|
929
|
+
saveMultiProfileConfig(multi);
|
|
930
|
+
}
|
|
931
|
+
function listProfiles() {
|
|
932
|
+
const multi = loadMultiProfileConfig();
|
|
933
|
+
return Object.entries(multi.profiles).map(([name, profile]) => ({
|
|
934
|
+
name,
|
|
935
|
+
isDefault: name === multi.defaultProfile,
|
|
936
|
+
teamId: profile.teamId
|
|
937
|
+
}));
|
|
938
|
+
}
|
|
939
|
+
function loadRawConfig(profileName) {
|
|
772
940
|
migrateFromLegacy();
|
|
773
941
|
const path = configPath();
|
|
774
942
|
if (!fs.existsSync(path)) return {};
|
|
775
|
-
|
|
943
|
+
let parsed;
|
|
944
|
+
try {
|
|
945
|
+
const raw = fs.readFileSync(path, "utf-8");
|
|
946
|
+
parsed = JSON.parse(raw);
|
|
947
|
+
} catch {
|
|
948
|
+
return {};
|
|
949
|
+
}
|
|
950
|
+
if (!isRecord2(parsed)) {
|
|
951
|
+
throw new Error(`Config file at ${path} must contain a JSON object.`);
|
|
952
|
+
}
|
|
953
|
+
if (isOldFormat(parsed)) {
|
|
954
|
+
return parseConfigFile(JSON.stringify(parsed), path, false, true);
|
|
955
|
+
}
|
|
956
|
+
const multi = migrateToMultiProfile(parsed, path);
|
|
957
|
+
const name = profileName || multi.defaultProfile || "default";
|
|
958
|
+
return multi.profiles[name] ?? {};
|
|
776
959
|
}
|
|
777
960
|
function getConfigPath() {
|
|
778
961
|
migrateFromLegacy();
|
|
779
962
|
return configPath();
|
|
780
963
|
}
|
|
781
|
-
function writeConfig(config) {
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
const filePath = join(dir, "config.json");
|
|
787
|
-
const apiToken = trimConfigValue(config.apiToken) ?? "";
|
|
788
|
-
const teamId = trimConfigValue(config.teamId) ?? "";
|
|
964
|
+
function writeConfig(config, profileName) {
|
|
965
|
+
const multi = loadMultiProfileConfig();
|
|
966
|
+
const name = profileName || multi.defaultProfile || "default";
|
|
967
|
+
const apiToken = trimConfigValue(config.apiToken) ?? void 0;
|
|
968
|
+
const teamId = trimConfigValue(config.teamId) ?? void 0;
|
|
789
969
|
const sprintFolderId = trimConfigValue(config.sprintFolderId);
|
|
790
970
|
const normalizedConfig = {
|
|
791
971
|
...apiToken ? { apiToken } : {},
|
|
792
972
|
...teamId ? { teamId } : {},
|
|
793
973
|
...sprintFolderId ? { sprintFolderId } : {}
|
|
794
974
|
};
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
}
|
|
975
|
+
multi.profiles[name] = {
|
|
976
|
+
...multi.profiles[name],
|
|
977
|
+
...normalizedConfig
|
|
978
|
+
};
|
|
979
|
+
if (!multi.defaultProfile) multi.defaultProfile = name;
|
|
980
|
+
saveMultiProfileConfig(multi);
|
|
799
981
|
}
|
|
800
982
|
|
|
801
983
|
// src/date.ts
|
|
@@ -2254,12 +2436,12 @@ function assertValidKey(key) {
|
|
|
2254
2436
|
throw new Error(`Unknown config key: ${key}. Valid keys: ${[...VALID_KEYS].join(", ")}`);
|
|
2255
2437
|
}
|
|
2256
2438
|
}
|
|
2257
|
-
function getConfigValue(key) {
|
|
2439
|
+
function getConfigValue(key, profileName) {
|
|
2258
2440
|
assertValidKey(key);
|
|
2259
|
-
const raw = loadRawConfig();
|
|
2441
|
+
const raw = loadRawConfig(profileName);
|
|
2260
2442
|
return readStoredString(raw[key]);
|
|
2261
2443
|
}
|
|
2262
|
-
function setConfigValue(key, value) {
|
|
2444
|
+
function setConfigValue(key, value, profileName) {
|
|
2263
2445
|
assertValidKey(key);
|
|
2264
2446
|
const normalizedValue = readStoredString(value);
|
|
2265
2447
|
if (key === "apiToken" && (!normalizedValue || !normalizedValue.startsWith("pk_"))) {
|
|
@@ -2268,7 +2450,7 @@ function setConfigValue(key, value) {
|
|
|
2268
2450
|
if (key === "teamId" && !normalizedValue) {
|
|
2269
2451
|
throw new Error("teamId must be non-empty");
|
|
2270
2452
|
}
|
|
2271
|
-
const raw = loadRawConfig();
|
|
2453
|
+
const raw = loadRawConfig(profileName);
|
|
2272
2454
|
const sprintFolderId = readStoredString(raw.sprintFolderId);
|
|
2273
2455
|
const merged = {
|
|
2274
2456
|
...readStoredString(raw.apiToken) ? { apiToken: readStoredString(raw.apiToken) } : {},
|
|
@@ -2284,7 +2466,7 @@ function setConfigValue(key, value) {
|
|
|
2284
2466
|
} else {
|
|
2285
2467
|
merged[key] = normalizedValue;
|
|
2286
2468
|
}
|
|
2287
|
-
writeConfig(merged);
|
|
2469
|
+
writeConfig(merged, profileName);
|
|
2288
2470
|
}
|
|
2289
2471
|
function configPath2() {
|
|
2290
2472
|
return getConfigPath();
|
|
@@ -2959,6 +3141,13 @@ var commandMetadata = [
|
|
|
2959
3141
|
flags: ["--json"],
|
|
2960
3142
|
quickReference: [{ section: "read", usage: "templates", description: "List task templates" }]
|
|
2961
3143
|
},
|
|
3144
|
+
{
|
|
3145
|
+
name: "profile",
|
|
3146
|
+
description: "Manage profiles",
|
|
3147
|
+
quickReference: [
|
|
3148
|
+
{ section: "configuration", usage: "profile", description: "Manage profiles" }
|
|
3149
|
+
]
|
|
3150
|
+
},
|
|
2962
3151
|
{
|
|
2963
3152
|
name: "config",
|
|
2964
3153
|
description: "Manage CLI configuration",
|
|
@@ -3015,7 +3204,14 @@ function topLevelCommandNames() {
|
|
|
3015
3204
|
}
|
|
3016
3205
|
|
|
3017
3206
|
// src/commands/completion.ts
|
|
3018
|
-
var bashSpecialCaseCommands = /* @__PURE__ */ new Set([
|
|
3207
|
+
var bashSpecialCaseCommands = /* @__PURE__ */ new Set([
|
|
3208
|
+
"checklist",
|
|
3209
|
+
"time",
|
|
3210
|
+
"bulk",
|
|
3211
|
+
"config",
|
|
3212
|
+
"profile",
|
|
3213
|
+
"completion"
|
|
3214
|
+
]);
|
|
3019
3215
|
function escapeSingleQuotes(value) {
|
|
3020
3216
|
return value.replaceAll("'", "'\\''");
|
|
3021
3217
|
}
|
|
@@ -3108,6 +3304,11 @@ ${renderBashCommandCases()}
|
|
|
3108
3304
|
COMPREPLY=($(compgen -W "status" -- "$cur"))
|
|
3109
3305
|
fi
|
|
3110
3306
|
;;
|
|
3307
|
+
profile)
|
|
3308
|
+
if [[ $cword -eq 2 ]]; then
|
|
3309
|
+
COMPREPLY=($(compgen -W "list add remove use" -- "$cur"))
|
|
3310
|
+
fi
|
|
3311
|
+
;;
|
|
3111
3312
|
config)
|
|
3112
3313
|
if [[ $cword -eq 2 ]]; then
|
|
3113
3314
|
COMPREPLY=($(compgen -W "get set path" -- "$cur"))
|
|
@@ -3645,6 +3846,33 @@ ${renderZshTopLevelCommands(name)}
|
|
|
3645
3846
|
'(-c --content)'{-c,--content}'[New page content]:text:' \\
|
|
3646
3847
|
'--json[Force JSON output]'
|
|
3647
3848
|
;;
|
|
3849
|
+
profile)
|
|
3850
|
+
local -a profile_cmds
|
|
3851
|
+
profile_cmds=(
|
|
3852
|
+
'list:List all profiles'
|
|
3853
|
+
'add:Add a new profile'
|
|
3854
|
+
'remove:Remove a profile'
|
|
3855
|
+
'use:Set the default profile'
|
|
3856
|
+
)
|
|
3857
|
+
_arguments -C \\
|
|
3858
|
+
'1:profile command:->profile_cmd' \\
|
|
3859
|
+
'*::profile_arg:->profile_args'
|
|
3860
|
+
case $state in
|
|
3861
|
+
profile_cmd)
|
|
3862
|
+
_describe 'profile command' profile_cmds
|
|
3863
|
+
;;
|
|
3864
|
+
profile_args)
|
|
3865
|
+
case $words[1] in
|
|
3866
|
+
list)
|
|
3867
|
+
_arguments '--json[Force JSON output]'
|
|
3868
|
+
;;
|
|
3869
|
+
add|remove|use)
|
|
3870
|
+
_arguments '1:name:'
|
|
3871
|
+
;;
|
|
3872
|
+
esac
|
|
3873
|
+
;;
|
|
3874
|
+
esac
|
|
3875
|
+
;;
|
|
3648
3876
|
config)
|
|
3649
3877
|
local -a config_cmds
|
|
3650
3878
|
config_cmds=(
|
|
@@ -3725,6 +3953,12 @@ complete -c ${name} -n '__fish_seen_subcommand_from attach' -F
|
|
|
3725
3953
|
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status' -a status -d 'Update status of multiple tasks'
|
|
3726
3954
|
complete -c ${name} -n '__fish_seen_subcommand_from status; and __fish_seen_subcommand_from bulk' -l json -d 'Force JSON output'
|
|
3727
3955
|
|
|
3956
|
+
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'
|
|
3957
|
+
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'
|
|
3958
|
+
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'
|
|
3959
|
+
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'
|
|
3960
|
+
complete -c ${name} -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from profile' -l json -d 'Force JSON output'
|
|
3961
|
+
|
|
3728
3962
|
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'
|
|
3729
3963
|
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'
|
|
3730
3964
|
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'
|
|
@@ -4551,7 +4785,10 @@ function parseOptionalNumberOption(value, optionName) {
|
|
|
4551
4785
|
}
|
|
4552
4786
|
function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
4553
4787
|
const program = new Command();
|
|
4554
|
-
program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false);
|
|
4788
|
+
program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false).option("-p, --profile <name>", "Use a specific profile");
|
|
4789
|
+
function getProfileName() {
|
|
4790
|
+
return program.opts().profile;
|
|
4791
|
+
}
|
|
4555
4792
|
program.command("init").description(`Set up ${programName} for the first time`).action(
|
|
4556
4793
|
wrapAction(async () => {
|
|
4557
4794
|
await runInitCommand();
|
|
@@ -4559,7 +4796,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4559
4796
|
);
|
|
4560
4797
|
program.command("auth").description("Validate API token and show current user").option("--json", "Force JSON output even in terminal").action(
|
|
4561
4798
|
wrapAction(async (opts) => {
|
|
4562
|
-
const config = loadConfig();
|
|
4799
|
+
const config = loadConfig(getProfileName());
|
|
4563
4800
|
const result = await checkAuth(config);
|
|
4564
4801
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4565
4802
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4575,7 +4812,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4575
4812
|
'Filter by task type (e.g. "task", "initiative", or custom type name/ID)'
|
|
4576
4813
|
).option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4577
4814
|
wrapAction(async (opts) => {
|
|
4578
|
-
const config = loadConfig();
|
|
4815
|
+
const config = loadConfig(getProfileName());
|
|
4579
4816
|
const tasks = await fetchMyTasks(config, {
|
|
4580
4817
|
typeFilter: opts.type,
|
|
4581
4818
|
statuses: opts.status ? [opts.status] : void 0,
|
|
@@ -4589,7 +4826,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4589
4826
|
);
|
|
4590
4827
|
program.command("task <taskId>").description("Get task details").option("--json", "Force JSON output even in terminal").action(
|
|
4591
4828
|
wrapAction(async (taskId, opts) => {
|
|
4592
|
-
const config = loadConfig();
|
|
4829
|
+
const config = loadConfig(getProfileName());
|
|
4593
4830
|
const result = await getTask(config, taskId);
|
|
4594
4831
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4595
4832
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4602,7 +4839,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4602
4839
|
);
|
|
4603
4840
|
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(
|
|
4604
4841
|
wrapAction(async (taskId, opts) => {
|
|
4605
|
-
const config = loadConfig();
|
|
4842
|
+
const config = loadConfig(getProfileName());
|
|
4606
4843
|
if (opts.assignee === "me") {
|
|
4607
4844
|
const client = new ClickUpClient(config);
|
|
4608
4845
|
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
@@ -4618,7 +4855,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4618
4855
|
);
|
|
4619
4856
|
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(
|
|
4620
4857
|
wrapAction(async (opts) => {
|
|
4621
|
-
const config = loadConfig();
|
|
4858
|
+
const config = loadConfig(getProfileName());
|
|
4622
4859
|
if (opts.assignee === "me") {
|
|
4623
4860
|
const client = new ClickUpClient(config);
|
|
4624
4861
|
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
@@ -4634,21 +4871,21 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4634
4871
|
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(
|
|
4635
4872
|
wrapAction(
|
|
4636
4873
|
async (opts) => {
|
|
4637
|
-
const config = loadConfig();
|
|
4874
|
+
const config = loadConfig(getProfileName());
|
|
4638
4875
|
await runSprintCommand(config, opts);
|
|
4639
4876
|
}
|
|
4640
4877
|
)
|
|
4641
4878
|
);
|
|
4642
4879
|
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(
|
|
4643
4880
|
wrapAction(async (opts) => {
|
|
4644
|
-
const config = loadConfig();
|
|
4881
|
+
const config = loadConfig(getProfileName());
|
|
4645
4882
|
await listSprints(config, opts);
|
|
4646
4883
|
})
|
|
4647
4884
|
);
|
|
4648
4885
|
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(
|
|
4649
4886
|
wrapAction(
|
|
4650
4887
|
async (taskId, opts) => {
|
|
4651
|
-
const config = loadConfig();
|
|
4888
|
+
const config = loadConfig(getProfileName());
|
|
4652
4889
|
let tasks = await fetchSubtasks(config, taskId, { includeClosed: opts.includeClosed });
|
|
4653
4890
|
if (opts.status) {
|
|
4654
4891
|
const lower = opts.status.toLowerCase();
|
|
@@ -4665,7 +4902,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4665
4902
|
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(
|
|
4666
4903
|
wrapAction(
|
|
4667
4904
|
async (taskId, opts) => {
|
|
4668
|
-
const config = loadConfig();
|
|
4905
|
+
const config = loadConfig(getProfileName());
|
|
4669
4906
|
const result = await postComment(config, taskId, opts.message, opts.notifyAll);
|
|
4670
4907
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4671
4908
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4677,7 +4914,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4677
4914
|
);
|
|
4678
4915
|
program.command("comments <taskId>").description("List comments on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4679
4916
|
wrapAction(async (taskId, opts) => {
|
|
4680
|
-
const config = loadConfig();
|
|
4917
|
+
const config = loadConfig(getProfileName());
|
|
4681
4918
|
const comments = await fetchComments(config, taskId);
|
|
4682
4919
|
printComments(comments, opts.json ?? false);
|
|
4683
4920
|
})
|
|
@@ -4685,7 +4922,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4685
4922
|
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(
|
|
4686
4923
|
wrapAction(
|
|
4687
4924
|
async (commentId, opts) => {
|
|
4688
|
-
const config = loadConfig();
|
|
4925
|
+
const config = loadConfig(getProfileName());
|
|
4689
4926
|
let resolved;
|
|
4690
4927
|
if (opts.resolved) resolved = true;
|
|
4691
4928
|
if (opts.unresolved) resolved = false;
|
|
@@ -4700,7 +4937,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4700
4937
|
);
|
|
4701
4938
|
program.command("comment-delete <commentId>").description("Delete a comment").option("--json", "Force JSON output even in terminal").action(
|
|
4702
4939
|
wrapAction(async (commentId, opts) => {
|
|
4703
|
-
const config = loadConfig();
|
|
4940
|
+
const config = loadConfig(getProfileName());
|
|
4704
4941
|
await deleteComment(config, commentId);
|
|
4705
4942
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4706
4943
|
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
@@ -4711,7 +4948,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4711
4948
|
);
|
|
4712
4949
|
program.command("replies <commentId>").description("List threaded replies on a comment").option("--json", "Force JSON output even in terminal").action(
|
|
4713
4950
|
wrapAction(async (commentId, opts) => {
|
|
4714
|
-
const config = loadConfig();
|
|
4951
|
+
const config = loadConfig(getProfileName());
|
|
4715
4952
|
const replies = await getReplies(config, commentId);
|
|
4716
4953
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4717
4954
|
console.log(JSON.stringify(replies, null, 2));
|
|
@@ -4725,7 +4962,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4725
4962
|
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(
|
|
4726
4963
|
wrapAction(
|
|
4727
4964
|
async (commentId, opts) => {
|
|
4728
|
-
const config = loadConfig();
|
|
4965
|
+
const config = loadConfig(getProfileName());
|
|
4729
4966
|
await createReply(config, commentId, opts.message, opts.notifyAll);
|
|
4730
4967
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4731
4968
|
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
@@ -4737,27 +4974,27 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4737
4974
|
);
|
|
4738
4975
|
program.command("activity <taskId>").description("Show task details and comments combined").option("--json", "Force JSON output even in terminal").action(
|
|
4739
4976
|
wrapAction(async (taskId, opts) => {
|
|
4740
|
-
const config = loadConfig();
|
|
4977
|
+
const config = loadConfig(getProfileName());
|
|
4741
4978
|
const result = await fetchActivity(config, taskId);
|
|
4742
4979
|
printActivity(result, opts.json ?? false);
|
|
4743
4980
|
})
|
|
4744
4981
|
);
|
|
4745
4982
|
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(
|
|
4746
4983
|
wrapAction(async (spaceId, opts) => {
|
|
4747
|
-
const config = loadConfig();
|
|
4984
|
+
const config = loadConfig(getProfileName());
|
|
4748
4985
|
const lists = await fetchLists(config, spaceId, { name: opts.name });
|
|
4749
4986
|
printLists(lists, opts.json ?? false);
|
|
4750
4987
|
})
|
|
4751
4988
|
);
|
|
4752
4989
|
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(
|
|
4753
4990
|
wrapAction(async (opts) => {
|
|
4754
|
-
const config = loadConfig();
|
|
4991
|
+
const config = loadConfig(getProfileName());
|
|
4755
4992
|
await listSpaces(config, opts);
|
|
4756
4993
|
})
|
|
4757
4994
|
);
|
|
4758
4995
|
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(
|
|
4759
4996
|
wrapAction(async (opts) => {
|
|
4760
|
-
const config = loadConfig();
|
|
4997
|
+
const config = loadConfig(getProfileName());
|
|
4761
4998
|
const days = Number(opts.days ?? 30);
|
|
4762
4999
|
if (!Number.isFinite(days) || days <= 0) {
|
|
4763
5000
|
throw new Error("--days must be a positive number");
|
|
@@ -4768,20 +5005,20 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4768
5005
|
);
|
|
4769
5006
|
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(
|
|
4770
5007
|
wrapAction(async (opts) => {
|
|
4771
|
-
const config = loadConfig();
|
|
5008
|
+
const config = loadConfig(getProfileName());
|
|
4772
5009
|
await runAssignedCommand(config, opts);
|
|
4773
5010
|
})
|
|
4774
5011
|
);
|
|
4775
5012
|
program.command("open <query>").description("Open a task in the browser by ID or name").option("--json", "Output task JSON instead of opening").action(
|
|
4776
5013
|
wrapAction(async (query, opts) => {
|
|
4777
|
-
const config = loadConfig();
|
|
5014
|
+
const config = loadConfig(getProfileName());
|
|
4778
5015
|
await openTask(config, query, opts);
|
|
4779
5016
|
})
|
|
4780
5017
|
);
|
|
4781
5018
|
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(
|
|
4782
5019
|
wrapAction(
|
|
4783
5020
|
async (query, opts) => {
|
|
4784
|
-
const config = loadConfig();
|
|
5021
|
+
const config = loadConfig(getProfileName());
|
|
4785
5022
|
const tasks = await searchTasks(config, query, {
|
|
4786
5023
|
status: opts.status,
|
|
4787
5024
|
includeClosed: opts.includeClosed
|
|
@@ -4792,7 +5029,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4792
5029
|
);
|
|
4793
5030
|
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(
|
|
4794
5031
|
wrapAction(async (opts) => {
|
|
4795
|
-
const config = loadConfig();
|
|
5032
|
+
const config = loadConfig(getProfileName());
|
|
4796
5033
|
const hours = Number(opts.hours ?? 24);
|
|
4797
5034
|
if (!Number.isFinite(hours) || hours <= 0) {
|
|
4798
5035
|
throw new Error("--hours must be a positive number");
|
|
@@ -4802,14 +5039,14 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4802
5039
|
);
|
|
4803
5040
|
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(
|
|
4804
5041
|
wrapAction(async (opts) => {
|
|
4805
|
-
const config = loadConfig();
|
|
5042
|
+
const config = loadConfig(getProfileName());
|
|
4806
5043
|
const tasks = await fetchOverdueTasks(config, { includeClosed: opts.includeClosed });
|
|
4807
5044
|
await printTasks(tasks, opts.json ?? false, config);
|
|
4808
5045
|
})
|
|
4809
5046
|
);
|
|
4810
5047
|
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(
|
|
4811
5048
|
wrapAction(async (taskId, opts) => {
|
|
4812
|
-
const config = loadConfig();
|
|
5049
|
+
const config = loadConfig(getProfileName());
|
|
4813
5050
|
const result = await assignTask(config, taskId, opts);
|
|
4814
5051
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4815
5052
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4820,7 +5057,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4820
5057
|
);
|
|
4821
5058
|
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(
|
|
4822
5059
|
wrapAction(async (taskId, opts) => {
|
|
4823
|
-
const config = loadConfig();
|
|
5060
|
+
const config = loadConfig(getProfileName());
|
|
4824
5061
|
const message = await manageDependency(config, taskId, opts);
|
|
4825
5062
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4826
5063
|
console.log(
|
|
@@ -4838,7 +5075,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4838
5075
|
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(
|
|
4839
5076
|
wrapAction(
|
|
4840
5077
|
async (taskId, linksTo, opts) => {
|
|
4841
|
-
const config = loadConfig();
|
|
5078
|
+
const config = loadConfig(getProfileName());
|
|
4842
5079
|
const result = await manageTaskLink(config, taskId, linksTo, opts.remove ?? false);
|
|
4843
5080
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4844
5081
|
console.log(
|
|
@@ -4856,7 +5093,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4856
5093
|
);
|
|
4857
5094
|
program.command("attach <taskId> <filePath>").description("Upload a file attachment to a task").option("--json", "Force JSON output even in terminal").action(
|
|
4858
5095
|
wrapAction(async (taskId, filePath, opts) => {
|
|
4859
|
-
const config = loadConfig();
|
|
5096
|
+
const config = loadConfig(getProfileName());
|
|
4860
5097
|
const result = await attachFile(config, taskId, filePath);
|
|
4861
5098
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4862
5099
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4868,7 +5105,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4868
5105
|
);
|
|
4869
5106
|
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(
|
|
4870
5107
|
wrapAction(async (taskId, opts) => {
|
|
4871
|
-
const config = loadConfig();
|
|
5108
|
+
const config = loadConfig(getProfileName());
|
|
4872
5109
|
const message = await moveTask(config, taskId, opts);
|
|
4873
5110
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4874
5111
|
console.log(
|
|
@@ -4882,7 +5119,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4882
5119
|
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(
|
|
4883
5120
|
wrapAction(
|
|
4884
5121
|
async (taskId, opts) => {
|
|
4885
|
-
const config = loadConfig();
|
|
5122
|
+
const config = loadConfig(getProfileName());
|
|
4886
5123
|
const fieldOpts = {};
|
|
4887
5124
|
if (opts.set) {
|
|
4888
5125
|
if (opts.set.length !== 2) {
|
|
@@ -4910,7 +5147,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4910
5147
|
);
|
|
4911
5148
|
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(
|
|
4912
5149
|
wrapAction(async (taskId, opts) => {
|
|
4913
|
-
const config = loadConfig();
|
|
5150
|
+
const config = loadConfig(getProfileName());
|
|
4914
5151
|
const result = await deleteTaskCommand(config, taskId, opts);
|
|
4915
5152
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4916
5153
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4922,7 +5159,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4922
5159
|
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(
|
|
4923
5160
|
wrapAction(
|
|
4924
5161
|
async (taskId, opts) => {
|
|
4925
|
-
const config = loadConfig();
|
|
5162
|
+
const config = loadConfig(getProfileName());
|
|
4926
5163
|
const result = await manageTags(config, taskId, opts);
|
|
4927
5164
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4928
5165
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4938,7 +5175,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4938
5175
|
const checklistCmd = program.command("checklist").description("Manage checklists on a task");
|
|
4939
5176
|
checklistCmd.command("view <taskId>").description("View checklists on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4940
5177
|
wrapAction(async (taskId, opts) => {
|
|
4941
|
-
const config = loadConfig();
|
|
5178
|
+
const config = loadConfig(getProfileName());
|
|
4942
5179
|
const checklists = await viewChecklists(config, taskId);
|
|
4943
5180
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4944
5181
|
console.log(JSON.stringify(checklists, null, 2));
|
|
@@ -4951,7 +5188,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4951
5188
|
);
|
|
4952
5189
|
checklistCmd.command("create <taskId> <name>").description("Create a checklist on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4953
5190
|
wrapAction(async (taskId, name, opts) => {
|
|
4954
|
-
const config = loadConfig();
|
|
5191
|
+
const config = loadConfig(getProfileName());
|
|
4955
5192
|
const result = await createChecklist(config, taskId, name);
|
|
4956
5193
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4957
5194
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4962,7 +5199,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4962
5199
|
);
|
|
4963
5200
|
checklistCmd.command("delete <checklistId>").description("Delete a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4964
5201
|
wrapAction(async (checklistId, opts) => {
|
|
4965
|
-
const config = loadConfig();
|
|
5202
|
+
const config = loadConfig(getProfileName());
|
|
4966
5203
|
const result = await deleteChecklist(config, checklistId);
|
|
4967
5204
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4968
5205
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4973,7 +5210,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4973
5210
|
);
|
|
4974
5211
|
checklistCmd.command("add-item <checklistId> <name>").description("Add an item to a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4975
5212
|
wrapAction(async (checklistId, name, opts) => {
|
|
4976
|
-
const config = loadConfig();
|
|
5213
|
+
const config = loadConfig(getProfileName());
|
|
4977
5214
|
const result = await addChecklistItem(config, checklistId, name);
|
|
4978
5215
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4979
5216
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4985,7 +5222,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4985
5222
|
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(
|
|
4986
5223
|
wrapAction(
|
|
4987
5224
|
async (checklistId, checklistItemId, opts) => {
|
|
4988
|
-
const config = loadConfig();
|
|
5225
|
+
const config = loadConfig(getProfileName());
|
|
4989
5226
|
const updates = {};
|
|
4990
5227
|
if (opts.name) updates.name = opts.name;
|
|
4991
5228
|
if (opts.resolved) updates.resolved = true;
|
|
@@ -5004,7 +5241,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5004
5241
|
);
|
|
5005
5242
|
checklistCmd.command("delete-item <checklistId> <checklistItemId>").description("Delete a checklist item").option("--json", "Force JSON output even in terminal").action(
|
|
5006
5243
|
wrapAction(async (checklistId, checklistItemId, opts) => {
|
|
5007
|
-
const config = loadConfig();
|
|
5244
|
+
const config = loadConfig(getProfileName());
|
|
5008
5245
|
const result = await deleteChecklistItem(config, checklistId, checklistItemId);
|
|
5009
5246
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5010
5247
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5016,7 +5253,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5016
5253
|
const timeCmd = program.command("time").description("Track time on tasks");
|
|
5017
5254
|
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(
|
|
5018
5255
|
wrapAction(async (taskId, opts) => {
|
|
5019
|
-
const config = loadConfig();
|
|
5256
|
+
const config = loadConfig(getProfileName());
|
|
5020
5257
|
const result = await startTimer(config, taskId, opts.description);
|
|
5021
5258
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5022
5259
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5028,7 +5265,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5028
5265
|
);
|
|
5029
5266
|
timeCmd.command("stop").description("Stop the running timer").option("--json", "Force JSON output even in terminal").action(
|
|
5030
5267
|
wrapAction(async (opts) => {
|
|
5031
|
-
const config = loadConfig();
|
|
5268
|
+
const config = loadConfig(getProfileName());
|
|
5032
5269
|
const result = await stopTimer(config);
|
|
5033
5270
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5034
5271
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5041,7 +5278,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5041
5278
|
);
|
|
5042
5279
|
timeCmd.command("status").description("Show the currently running timer").option("--json", "Force JSON output even in terminal").action(
|
|
5043
5280
|
wrapAction(async (opts) => {
|
|
5044
|
-
const config = loadConfig();
|
|
5281
|
+
const config = loadConfig(getProfileName());
|
|
5045
5282
|
const result = await timerStatus(config);
|
|
5046
5283
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5047
5284
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5057,7 +5294,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5057
5294
|
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(
|
|
5058
5295
|
wrapAction(
|
|
5059
5296
|
async (taskId, duration, opts) => {
|
|
5060
|
-
const config = loadConfig();
|
|
5297
|
+
const config = loadConfig(getProfileName());
|
|
5061
5298
|
const result = await logTime(config, taskId, duration, opts.description);
|
|
5062
5299
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5063
5300
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5069,7 +5306,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5069
5306
|
);
|
|
5070
5307
|
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(
|
|
5071
5308
|
wrapAction(async (opts) => {
|
|
5072
|
-
const config = loadConfig();
|
|
5309
|
+
const config = loadConfig(getProfileName());
|
|
5073
5310
|
const days = opts.days ? Number(opts.days) : 7;
|
|
5074
5311
|
if (!Number.isFinite(days) || days <= 0) {
|
|
5075
5312
|
throw new Error("--days must be a positive number");
|
|
@@ -5087,7 +5324,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5087
5324
|
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(
|
|
5088
5325
|
wrapAction(
|
|
5089
5326
|
async (timeEntryId, opts) => {
|
|
5090
|
-
const config = loadConfig();
|
|
5327
|
+
const config = loadConfig(getProfileName());
|
|
5091
5328
|
const entry = await updateTimeEntry(config, timeEntryId, {
|
|
5092
5329
|
description: opts.description,
|
|
5093
5330
|
duration: opts.duration
|
|
@@ -5104,7 +5341,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5104
5341
|
);
|
|
5105
5342
|
timeCmd.command("delete <timeEntryId>").description("Delete a time entry").option("--json", "Force JSON output even in terminal").action(
|
|
5106
5343
|
wrapAction(async (timeEntryId, opts) => {
|
|
5107
|
-
const config = loadConfig();
|
|
5344
|
+
const config = loadConfig(getProfileName());
|
|
5108
5345
|
await deleteTimeEntry(config, timeEntryId);
|
|
5109
5346
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5110
5347
|
console.log(JSON.stringify({ deleted: timeEntryId }));
|
|
@@ -5115,7 +5352,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5115
5352
|
);
|
|
5116
5353
|
program.command("tags <spaceId>").description("List tags in a space").option("--json", "Force JSON output even in terminal").action(
|
|
5117
5354
|
wrapAction(async (spaceId, opts) => {
|
|
5118
|
-
const config = loadConfig();
|
|
5355
|
+
const config = loadConfig(getProfileName());
|
|
5119
5356
|
const tags = await listSpaceTags(config, spaceId);
|
|
5120
5357
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5121
5358
|
console.log(JSON.stringify(tags, null, 2));
|
|
@@ -5129,7 +5366,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5129
5366
|
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(
|
|
5130
5367
|
wrapAction(
|
|
5131
5368
|
async (spaceId, name, opts) => {
|
|
5132
|
-
const config = loadConfig();
|
|
5369
|
+
const config = loadConfig(getProfileName());
|
|
5133
5370
|
await createSpaceTag(config, spaceId, name, opts.fg, opts.bg);
|
|
5134
5371
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5135
5372
|
console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
|
|
@@ -5141,7 +5378,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5141
5378
|
);
|
|
5142
5379
|
program.command("tag-delete <spaceId> <name>").description("Delete a tag from a space").option("--json", "Force JSON output even in terminal").action(
|
|
5143
5380
|
wrapAction(async (spaceId, name, opts) => {
|
|
5144
|
-
const config = loadConfig();
|
|
5381
|
+
const config = loadConfig(getProfileName());
|
|
5145
5382
|
await deleteSpaceTag(config, spaceId, name);
|
|
5146
5383
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5147
5384
|
console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
|
|
@@ -5152,7 +5389,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5152
5389
|
);
|
|
5153
5390
|
program.command("members").description("List workspace members").option("--json", "Force JSON output even in terminal").action(
|
|
5154
5391
|
wrapAction(async (opts) => {
|
|
5155
|
-
const config = loadConfig();
|
|
5392
|
+
const config = loadConfig(getProfileName());
|
|
5156
5393
|
const members = await listMembers(config);
|
|
5157
5394
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5158
5395
|
console.log(JSON.stringify(members, null, 2));
|
|
@@ -5165,7 +5402,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5165
5402
|
);
|
|
5166
5403
|
program.command("fields <listId>").description("List custom fields for a list").option("--json", "Force JSON output even in terminal").action(
|
|
5167
5404
|
wrapAction(async (listId, opts) => {
|
|
5168
|
-
const config = loadConfig();
|
|
5405
|
+
const config = loadConfig(getProfileName());
|
|
5169
5406
|
const fields = await listFields(config, listId);
|
|
5170
5407
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5171
5408
|
console.log(JSON.stringify(fields, null, 2));
|
|
@@ -5178,7 +5415,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5178
5415
|
);
|
|
5179
5416
|
program.command("duplicate <taskId>").description("Duplicate a task").option("--json", "Force JSON output even in terminal").action(
|
|
5180
5417
|
wrapAction(async (taskId, opts) => {
|
|
5181
|
-
const config = loadConfig();
|
|
5418
|
+
const config = loadConfig(getProfileName());
|
|
5182
5419
|
const result = await duplicateTask(config, taskId);
|
|
5183
5420
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5184
5421
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5190,7 +5427,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5190
5427
|
const bulkCmd = program.command("bulk").description("Bulk task operations");
|
|
5191
5428
|
bulkCmd.command("status <status> <taskIds...>").description("Update status of multiple tasks").option("--json", "Force JSON output even in terminal").action(
|
|
5192
5429
|
wrapAction(async (status, taskIds, opts) => {
|
|
5193
|
-
const config = loadConfig();
|
|
5430
|
+
const config = loadConfig(getProfileName());
|
|
5194
5431
|
const result = await bulkUpdateStatus(config, taskIds, status);
|
|
5195
5432
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5196
5433
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5206,7 +5443,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5206
5443
|
);
|
|
5207
5444
|
program.command("goals").description("List goals in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5208
5445
|
wrapAction(async (opts) => {
|
|
5209
|
-
const config = loadConfig();
|
|
5446
|
+
const config = loadConfig(getProfileName());
|
|
5210
5447
|
const goals = await listGoals(config);
|
|
5211
5448
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5212
5449
|
console.log(JSON.stringify(goals, null, 2));
|
|
@@ -5220,7 +5457,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5220
5457
|
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(
|
|
5221
5458
|
wrapAction(
|
|
5222
5459
|
async (name, opts) => {
|
|
5223
|
-
const config = loadConfig();
|
|
5460
|
+
const config = loadConfig(getProfileName());
|
|
5224
5461
|
const goal = await createGoal(config, name, {
|
|
5225
5462
|
description: opts.description,
|
|
5226
5463
|
color: opts.color
|
|
@@ -5236,7 +5473,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5236
5473
|
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(
|
|
5237
5474
|
wrapAction(
|
|
5238
5475
|
async (goalId, opts) => {
|
|
5239
|
-
const config = loadConfig();
|
|
5476
|
+
const config = loadConfig(getProfileName());
|
|
5240
5477
|
const goal = await updateGoal(config, goalId, {
|
|
5241
5478
|
name: opts.name,
|
|
5242
5479
|
description: opts.description,
|
|
@@ -5252,7 +5489,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5252
5489
|
);
|
|
5253
5490
|
program.command("goal-delete <goalId>").description("Delete a goal").option("--json", "Force JSON output even in terminal").action(
|
|
5254
5491
|
wrapAction(async (goalId, opts) => {
|
|
5255
|
-
const config = loadConfig();
|
|
5492
|
+
const config = loadConfig(getProfileName());
|
|
5256
5493
|
await deleteGoal(config, goalId);
|
|
5257
5494
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5258
5495
|
console.log(JSON.stringify({ success: true, goalId }, null, 2));
|
|
@@ -5263,7 +5500,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5263
5500
|
);
|
|
5264
5501
|
program.command("key-results <goalId>").description("List key results for a goal").option("--json", "Force JSON output even in terminal").action(
|
|
5265
5502
|
wrapAction(async (goalId, opts) => {
|
|
5266
|
-
const config = loadConfig();
|
|
5503
|
+
const config = loadConfig(getProfileName());
|
|
5267
5504
|
const krs = await listKeyResults(config, goalId);
|
|
5268
5505
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5269
5506
|
console.log(JSON.stringify(krs, null, 2));
|
|
@@ -5277,7 +5514,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5277
5514
|
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(
|
|
5278
5515
|
wrapAction(
|
|
5279
5516
|
async (goalId, name, opts) => {
|
|
5280
|
-
const config = loadConfig();
|
|
5517
|
+
const config = loadConfig(getProfileName());
|
|
5281
5518
|
const target = Number(opts.target ?? 100);
|
|
5282
5519
|
if (!Number.isFinite(target) || target <= 0) {
|
|
5283
5520
|
throw new Error("--target must be a positive number");
|
|
@@ -5294,7 +5531,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5294
5531
|
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(
|
|
5295
5532
|
wrapAction(
|
|
5296
5533
|
async (keyResultId, opts) => {
|
|
5297
|
-
const config = loadConfig();
|
|
5534
|
+
const config = loadConfig(getProfileName());
|
|
5298
5535
|
const updates = {};
|
|
5299
5536
|
if (opts.progress !== void 0) {
|
|
5300
5537
|
const p = Number(opts.progress);
|
|
@@ -5313,7 +5550,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5313
5550
|
);
|
|
5314
5551
|
program.command("key-result-delete <keyResultId>").description("Delete a key result").option("--json", "Force JSON output even in terminal").action(
|
|
5315
5552
|
wrapAction(async (keyResultId, opts) => {
|
|
5316
|
-
const config = loadConfig();
|
|
5553
|
+
const config = loadConfig(getProfileName());
|
|
5317
5554
|
await deleteKeyResult(config, keyResultId);
|
|
5318
5555
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5319
5556
|
console.log(JSON.stringify({ success: true, keyResultId }, null, 2));
|
|
@@ -5324,7 +5561,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5324
5561
|
);
|
|
5325
5562
|
program.command("docs [query]").description("List workspace docs (optionally filter by name)").option("--json", "Force JSON output even in terminal").action(
|
|
5326
5563
|
wrapAction(async (query, opts) => {
|
|
5327
|
-
const config = loadConfig();
|
|
5564
|
+
const config = loadConfig(getProfileName());
|
|
5328
5565
|
const docs = await listDocs(config, query);
|
|
5329
5566
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5330
5567
|
console.log(JSON.stringify(docs, null, 2));
|
|
@@ -5337,7 +5574,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5337
5574
|
);
|
|
5338
5575
|
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(
|
|
5339
5576
|
wrapAction(async (docId, pageId, opts) => {
|
|
5340
|
-
const config = loadConfig();
|
|
5577
|
+
const config = loadConfig(getProfileName());
|
|
5341
5578
|
if (pageId) {
|
|
5342
5579
|
const page = await getDocPage(config, docId, pageId);
|
|
5343
5580
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
@@ -5361,7 +5598,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5361
5598
|
);
|
|
5362
5599
|
program.command("doc-pages <docId>").description("List all pages in a doc with content").option("--json", "Force JSON output even in terminal").action(
|
|
5363
5600
|
wrapAction(async (docId, opts) => {
|
|
5364
|
-
const config = loadConfig();
|
|
5601
|
+
const config = loadConfig(getProfileName());
|
|
5365
5602
|
const pages = await getAllDocPages(config, docId);
|
|
5366
5603
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5367
5604
|
console.log(JSON.stringify(pages, null, 2));
|
|
@@ -5374,7 +5611,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5374
5611
|
);
|
|
5375
5612
|
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(
|
|
5376
5613
|
wrapAction(async (spaceId, opts) => {
|
|
5377
|
-
const config = loadConfig();
|
|
5614
|
+
const config = loadConfig(getProfileName());
|
|
5378
5615
|
const folders = await listFolders(config, spaceId, opts.name);
|
|
5379
5616
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5380
5617
|
console.log(JSON.stringify(folders, null, 2));
|
|
@@ -5387,7 +5624,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5387
5624
|
);
|
|
5388
5625
|
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(
|
|
5389
5626
|
wrapAction(async (title, opts) => {
|
|
5390
|
-
const config = loadConfig();
|
|
5627
|
+
const config = loadConfig(getProfileName());
|
|
5391
5628
|
const result = await createDoc(config, title, opts.content);
|
|
5392
5629
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5393
5630
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5399,7 +5636,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5399
5636
|
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(
|
|
5400
5637
|
wrapAction(
|
|
5401
5638
|
async (docId, name, opts) => {
|
|
5402
|
-
const config = loadConfig();
|
|
5639
|
+
const config = loadConfig(getProfileName());
|
|
5403
5640
|
const page = await createDocPage(config, docId, name, opts.content, opts.parentPage);
|
|
5404
5641
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5405
5642
|
console.log(JSON.stringify(page, null, 2));
|
|
@@ -5412,7 +5649,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5412
5649
|
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(
|
|
5413
5650
|
wrapAction(
|
|
5414
5651
|
async (docId, pageId, opts) => {
|
|
5415
|
-
const config = loadConfig();
|
|
5652
|
+
const config = loadConfig(getProfileName());
|
|
5416
5653
|
const page = await editDocPage(config, docId, pageId, {
|
|
5417
5654
|
name: opts.name,
|
|
5418
5655
|
content: opts.content
|
|
@@ -5427,7 +5664,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5427
5664
|
);
|
|
5428
5665
|
program.command("doc-delete <docId>").description("Delete a doc").option("--json", "Force JSON output even in terminal").action(
|
|
5429
5666
|
wrapAction(async (docId, opts) => {
|
|
5430
|
-
const config = loadConfig();
|
|
5667
|
+
const config = loadConfig(getProfileName());
|
|
5431
5668
|
await deleteDoc(config, docId);
|
|
5432
5669
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5433
5670
|
console.log(JSON.stringify({ success: true, docId }, null, 2));
|
|
@@ -5438,7 +5675,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5438
5675
|
);
|
|
5439
5676
|
program.command("doc-page-delete <docId> <pageId>").description("Delete a doc page").option("--json", "Force JSON output even in terminal").action(
|
|
5440
5677
|
wrapAction(async (docId, pageId, opts) => {
|
|
5441
|
-
const config = loadConfig();
|
|
5678
|
+
const config = loadConfig(getProfileName());
|
|
5442
5679
|
await deleteDocPage(config, docId, pageId);
|
|
5443
5680
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5444
5681
|
console.log(JSON.stringify({ success: true, docId, pageId }, null, 2));
|
|
@@ -5450,7 +5687,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5450
5687
|
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(
|
|
5451
5688
|
wrapAction(
|
|
5452
5689
|
async (spaceId, tagName, opts) => {
|
|
5453
|
-
const config = loadConfig();
|
|
5690
|
+
const config = loadConfig(getProfileName());
|
|
5454
5691
|
await updateSpaceTag(config, spaceId, tagName, {
|
|
5455
5692
|
name: opts.name,
|
|
5456
5693
|
fg: opts.fg,
|
|
@@ -5472,7 +5709,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5472
5709
|
);
|
|
5473
5710
|
program.command("task-types").description("List custom task types in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5474
5711
|
wrapAction(async (opts) => {
|
|
5475
|
-
const config = loadConfig();
|
|
5712
|
+
const config = loadConfig(getProfileName());
|
|
5476
5713
|
const types = await listTaskTypes(config);
|
|
5477
5714
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5478
5715
|
console.log(JSON.stringify(types, null, 2));
|
|
@@ -5485,7 +5722,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5485
5722
|
);
|
|
5486
5723
|
program.command("templates").description("List task templates in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5487
5724
|
wrapAction(async (opts) => {
|
|
5488
|
-
const config = loadConfig();
|
|
5725
|
+
const config = loadConfig(getProfileName());
|
|
5489
5726
|
const templates = await listTemplates(config);
|
|
5490
5727
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5491
5728
|
console.log(JSON.stringify(templates, null, 2));
|
|
@@ -5496,10 +5733,65 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5496
5733
|
}
|
|
5497
5734
|
})
|
|
5498
5735
|
);
|
|
5736
|
+
const profileCmd = program.command("profile").description("Manage profiles");
|
|
5737
|
+
profileCmd.command("list").description("List all profiles").option("--json", "Force JSON output even in terminal").action(
|
|
5738
|
+
wrapAction(async (opts) => {
|
|
5739
|
+
const profiles = listProfiles();
|
|
5740
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5741
|
+
console.log(JSON.stringify(profiles, null, 2));
|
|
5742
|
+
} else {
|
|
5743
|
+
for (const p of profiles) {
|
|
5744
|
+
const marker = p.isDefault ? " (default)" : "";
|
|
5745
|
+
console.log(`${p.name}${marker}${p.teamId ? ` [team: ${p.teamId}]` : ""}`);
|
|
5746
|
+
}
|
|
5747
|
+
if (profiles.length === 0)
|
|
5748
|
+
console.log("No profiles configured. Run: cup profile add <name>");
|
|
5749
|
+
}
|
|
5750
|
+
})
|
|
5751
|
+
);
|
|
5752
|
+
profileCmd.command("add <name>").description("Add a new profile").action(
|
|
5753
|
+
wrapAction(async (name) => {
|
|
5754
|
+
const { password: password2, select: select3 } = await import("@inquirer/prompts");
|
|
5755
|
+
const apiToken = (await password2({ message: "ClickUp API token (pk_...):" })).trim();
|
|
5756
|
+
if (!apiToken.startsWith("pk_")) throw new Error("Token must start with pk_");
|
|
5757
|
+
const client = new ClickUpClient({ apiToken });
|
|
5758
|
+
const me = await client.getMe();
|
|
5759
|
+
process.stdout.write(`Authenticated as @${me.username}
|
|
5760
|
+
`);
|
|
5761
|
+
const teams = await client.getTeams();
|
|
5762
|
+
if (teams.length === 0) throw new Error("No workspaces found for this token.");
|
|
5763
|
+
let teamId;
|
|
5764
|
+
if (teams.length === 1) {
|
|
5765
|
+
teamId = teams[0].id;
|
|
5766
|
+
process.stdout.write(`Workspace: ${teams[0].name}
|
|
5767
|
+
`);
|
|
5768
|
+
} else {
|
|
5769
|
+
teamId = await select3({
|
|
5770
|
+
message: "Select workspace:",
|
|
5771
|
+
choices: teams.map((t) => ({ name: t.name, value: t.id }))
|
|
5772
|
+
});
|
|
5773
|
+
}
|
|
5774
|
+
addProfile(name, { apiToken, teamId });
|
|
5775
|
+
process.stdout.write(`Profile "${name}" added.
|
|
5776
|
+
`);
|
|
5777
|
+
})
|
|
5778
|
+
);
|
|
5779
|
+
profileCmd.command("remove <name>").description("Remove a profile").action(
|
|
5780
|
+
wrapAction(async (name) => {
|
|
5781
|
+
removeProfile(name);
|
|
5782
|
+
console.log(`Removed profile "${name}"`);
|
|
5783
|
+
})
|
|
5784
|
+
);
|
|
5785
|
+
profileCmd.command("use <name>").description("Set the default profile").action(
|
|
5786
|
+
wrapAction(async (name) => {
|
|
5787
|
+
setDefaultProfile(name);
|
|
5788
|
+
console.log(`Default profile set to "${name}"`);
|
|
5789
|
+
})
|
|
5790
|
+
);
|
|
5499
5791
|
const configCmd = program.command("config").description("Manage CLI configuration");
|
|
5500
5792
|
configCmd.command("get <key>").description("Print a config value").action(
|
|
5501
5793
|
wrapAction(async (key) => {
|
|
5502
|
-
const value = getConfigValue(key);
|
|
5794
|
+
const value = getConfigValue(key, getProfileName());
|
|
5503
5795
|
if (value !== void 0) {
|
|
5504
5796
|
console.log(value);
|
|
5505
5797
|
}
|
|
@@ -5507,7 +5799,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5507
5799
|
);
|
|
5508
5800
|
configCmd.command("set <key> <value>").description("Set a config value").action(
|
|
5509
5801
|
wrapAction(async (key, value) => {
|
|
5510
|
-
setConfigValue(key, value);
|
|
5802
|
+
setConfigValue(key, value, getProfileName());
|
|
5511
5803
|
})
|
|
5512
5804
|
);
|
|
5513
5805
|
configCmd.command("path").description("Print config file path").action(
|
|
@@ -5532,7 +5824,12 @@ process.on("SIGINT", () => {
|
|
|
5532
5824
|
process.stderr.write("\nInterrupted\n");
|
|
5533
5825
|
process.exit(130);
|
|
5534
5826
|
});
|
|
5535
|
-
var isDirectExecution =
|
|
5827
|
+
var isDirectExecution = false;
|
|
5828
|
+
try {
|
|
5829
|
+
isDirectExecution = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
|
|
5830
|
+
} catch {
|
|
5831
|
+
isDirectExecution = false;
|
|
5832
|
+
}
|
|
5536
5833
|
if (isDirectExecution) {
|
|
5537
5834
|
await run();
|
|
5538
5835
|
}
|
package/package.json
CHANGED
|
@@ -9,9 +9,11 @@ Reference for AI agents using the `cup` CLI tool. Covers task management, sprint
|
|
|
9
9
|
|
|
10
10
|
## Setup
|
|
11
11
|
|
|
12
|
-
Config at `~/.config/cup/config.json` with `apiToken` and `teamId`. Optional: `sprintFolderId` to pin sprint detection to a specific folder. Run `cup init` to set up interactively.
|
|
12
|
+
Config at `~/.config/cup/config.json` with named profiles. Each profile has `apiToken` and `teamId`. Optional: `sprintFolderId` to pin sprint detection to a specific folder. Run `cup init` to set up interactively.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Multiple profiles supported - use `cup profile add <name>` to create, `cup profile use <name>` to switch, or `-p <name>` flag for one-off overrides.
|
|
15
|
+
|
|
16
|
+
Environment variables `CU_API_TOKEN` and `CU_TEAM_ID` override config file when both are set. `CU_PROFILE` selects a profile (overridden by `-p` flag).
|
|
15
17
|
|
|
16
18
|
## Output Modes
|
|
17
19
|
|
|
@@ -109,9 +111,20 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
109
111
|
| `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
|
|
110
112
|
| `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
|
|
111
113
|
| `cup tag-delete <spaceId> <name>` | Delete space tag |
|
|
114
|
+
| `cup profile list [--json]` | List all profiles |
|
|
115
|
+
| `cup profile add <name>` | Add a new profile (interactive) |
|
|
116
|
+
| `cup profile remove <name>` | Remove a profile |
|
|
117
|
+
| `cup profile use <name>` | Set the default profile |
|
|
112
118
|
| `cup config get <key>` / `set <key> <value>` / `path` | Manage config |
|
|
113
119
|
| `cup completion <shell>` | Shell completions (bash/zsh/fish) |
|
|
114
120
|
|
|
121
|
+
## Global Flags
|
|
122
|
+
|
|
123
|
+
| Flag | Description |
|
|
124
|
+
| ------------------- | --------------------------------------------- |
|
|
125
|
+
| `-p, --profile <n>` | Use a specific profile for this command |
|
|
126
|
+
| `--json` | Force JSON output (available on all commands) |
|
|
127
|
+
|
|
115
128
|
## Flags & Conventions
|
|
116
129
|
|
|
117
130
|
| Topic | Detail |
|
|
@@ -218,6 +231,15 @@ cup key-result-create g123 "API coverage" --type percentage --target 80
|
|
|
218
231
|
cup key-result-update kr456 --progress 60 --note "On track"
|
|
219
232
|
```
|
|
220
233
|
|
|
234
|
+
### Profiles
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
cup profile add personal # add a profile (interactive)
|
|
238
|
+
cup profile list # list all profiles
|
|
239
|
+
cup profile use personal # switch default
|
|
240
|
+
cup tasks -p work # use specific profile for one command
|
|
241
|
+
```
|
|
242
|
+
|
|
221
243
|
### Standup
|
|
222
244
|
|
|
223
245
|
```bash
|